package com.ncloud.auth.service.impl;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import java.util.UUID;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.ncloud.auth.config.Constant;
import com.ncloud.auth.service.AuthService;
import com.ncloud.auth.service.TokenConfig;
import com.ncloud.auth.util.JWT;
import com.ncloud.common.enmus.ResultEnum;
import com.ncloud.common.exception.UserException;
import com.ncloud.common.utils.DateUtils;
import com.ncloud.common.utils.Encodes;
import com.ncloud.common.utils.EncryptUtils;
import com.ncloud.common.utils.RedisUtils;
import com.ncloud.system.constant.UserConstant;
import com.ncloud.system.entity.Email;
import com.ncloud.system.entity.User;
import com.ncloud.system.service.CompanyService;
import com.ncloud.system.service.MailService;
import com.ncloud.system.service.UserAuthService;
import com.ncloud.system.service.UserService;

import io.jsonwebtoken.Claims;

@Service
public class AuthServiceImpl implements AuthService{
	@Autowired
	private UserService userService;
	@Autowired
	private RedisUtils redisUtils;
	@Autowired
	private TokenConfig tokenConfig;
	@Autowired
	private UserAuthService userAuthService;
	@Autowired
	private MailService mailService;
	@Autowired
	private CompanyService companyService;
	
	/**
	 * //获取User数据（redis和数据库）两种情况
		// 判断用户是否匹配
		// 1.用户不存在
		// 2.密码不正确
		// 3.用户被锁定
		// 暂时不处理用户输入密码错误次数问题
		// 生成token
		// 返回
	 */
	@Override
	public JSONObject login(String userName, String password) {
		User user = null;
		boolean firstLogin = false;
		JSONObject json = new JSONObject();
		try {
			//从redis中获取
			user = redisUtils.getBean(UserConstant.REDIS_USER_INFO_PREFIX+userName, User.class);
		} catch (Exception e) {
			user = null;
		}
		if (user==null) {
			user = userService.findByUsername(userName);
		}
		
		if(user==null) throw new UserException(ResultEnum.USER_NOT_FOUND);
		
		//判断企业是否锁定
		Integer state = companyService.getCompanyStateById(user.getCompanyId().intValue());
		if(state==1){
			throw new UserException(ResultEnum.COMPANY_LOCK);
		}
		
		// 用户锁定
		if(UserConstant.USER_STATE_LOCK.equals(user.getState())){
			throw new UserException(ResultEnum.USER_LOCK);
		}
		
		//判断首次登陆
		if(user.getFirstLoginTime()==null){
			firstLogin = true;
			user.setFirstLoginTime(new Date());
			userService.updateFirstLoginTime(user);
		}
		
		redisUtils.set(UserConstant.REDIS_USER_INFO_PREFIX+userName, user, UserConstant._USER_INFO_USERNAME_EXPIRETIME);
		if(!redisUtils.exists(UserConstant.REDIS_ERROR_TIME_PREFIX+userName)){
			redisUtils.setSeq(UserConstant.REDIS_ERROR_TIME_PREFIX+userName, 0);
		}
		
		if(!EncryptUtils.encryptSHA(password).equals(user.getPasswd())){
			long errTimes = redisUtils.getSeqNext(UserConstant.REDIS_ERROR_TIME_PREFIX+userName);
			if(errTimes>=3){
				userService.lockUser(user.getUserId());
				throw new UserException(ResultEnum.USER_LOCK_OVER3);
			}
			redisUtils.set(UserConstant.REDIS_ERROR_TIME_PREFIX+userName, errTimes, UserConstant._ERROR_TIME_EXPIRETIME);
			throw new UserException(ResultEnum.USER_PASSWD_ERROR);
		}
		
		redisUtils.set(UserConstant.REDIS_ERROR_TIME_PREFIX+userName, 0, UserConstant._ERROR_TIME_EXPIRETIME);
		Map<String, Object> claims = new HashMap<String, Object>();
		String userID = user.getUserId()+"";
		claims.put("userID", userID);
		claims.put("account",user.getAccount());
		
		Random random = new Random();
        String roundId = System.currentTimeMillis()+""+random.nextInt(100);
        claims.put("roundId", roundId);
		String token = JWT.createJWT(userID, userID, Constant.tokenExpiredTime, claims);
		String refreshToken = JWT.createJWT(userID, userID, Constant.refreshTokenExpiredTime, claims);
		redisUtils.set(tokenConfig.getTokenName(userID, roundId), token, Constant.tokenExpiredTime);
		redisUtils.set(tokenConfig.getRefreshTokenName(userID, roundId), refreshToken, Constant.refreshTokenExpiredTime);
		redisUtils.set(tokenConfig.getUserInfoName(userID, roundId), claims, Constant.refreshTokenExpiredTime);
		
		json.put("token", token);
		json.put("freshToken", refreshToken);
		json.put("firstLogin", firstLogin);
		return json;
	}

	@Override
	public String refresh(String refreshToken) {
		if(StringUtils.isBlank(refreshToken)){
			throw new UserException(ResultEnum.PARAM_ERROR);
		}
		String token = "";
		Claims claims = JWT.parseJWT(refreshToken);
		String userID = claims.get("userID", String.class);
	    String roundId = claims.get("roundId", String.class);
	    String redisFreshToken = redisUtils.getString(tokenConfig.getRefreshTokenName(userID, roundId));
	    if(StringUtils.isNoneBlank(redisFreshToken)){
	    	@SuppressWarnings("unchecked")
			HashMap<String, Object> param = (HashMap<String, Object>) redisUtils.get(tokenConfig.getUserInfoName(userID,roundId));
	    	token = JWT.createJWT(userID, userID, Constant.tokenExpiredTime, param);
	    	redisUtils.set(tokenConfig.getTokenName(userID, roundId), token, Constant.tokenExpiredTime);
	    	redisUtils.expire(tokenConfig.getRefreshTokenName(userID, roundId), Constant.refreshTokenExpiredTime);
	    	redisUtils.expire(tokenConfig.getUserInfoName(userID, roundId), Constant.refreshTokenExpiredTime);
	    }
		return token;
	}

	@Override
	public void destroy(String token) {
		if(StringUtils.isBlank(token)){
			throw new UserException(ResultEnum.PARAM_ERROR);
		}
		Claims claims = JWT.parseJWT(token);
		String userID = claims.get("userID", String.class);
	    String roundId = claims.get("roundId", String.class);
	    redisUtils.remove(tokenConfig.getTokenName(userID, roundId),tokenConfig.getRefreshTokenName(userID, roundId),
	    		tokenConfig.getUserInfoName(userID, roundId));
	    
	}

	@Override
	@Transactional
	public void forgetPassword(String userName) {
		// 判断用户是否存在
		User user = userService.findByUsername(userName);
		if(user==null) throw new UserException(ResultEnum.USER_NOT_FOUND);
		// 生成authCode
		String uuid = UUID.randomUUID().toString();
		String authCode = Encodes.encodeBase64(userName+uuid);
		userAuthService.save(user.getUserId(),authCode);
		// 存在则发送邮件
		geneSendMailReady(userName,authCode);
		
	}

	private void geneSendMailReady(String userName, String authCode) {
		Email email = new Email();
		email.setSysCode("system");
		String subject = "鹏博士 -- 找回密码";
		email.setSubject(subject);
		email.setMsgTo(userName);
		JSONObject content = new JSONObject();
		content.put("userName", userName);
		content.put("authCode", authCode);
		content.put("sendDate", DateUtils.getDate());
		email.setContent(JSON.toJSONString(content));
		email.setTemplateName("forgetPassword.ftl");
		email.setMsgType("1");
		mailService.insertEmail(email);
	}

	@Override
	public Long checkAuthCode(String authCode) {
		if(StringUtils.isBlank(authCode)){
			throw new UserException(ResultEnum.PARAM_ERROR);
		}
		// 判断redis中是否存在
		Long userId = null;
		if(redisUtils.exists(UserConstant.REDIS_USER_AUTH_PREFIX + authCode)){
			userId = (Long) redisUtils.get(UserConstant.REDIS_USER_AUTH_PREFIX + authCode);
		}else{
			throw new UserException(ResultEnum.AUTH_CODE_CHECK_ERROR);
		}
		return userId;
	}

	@Override
	public void resetPassword(Long userId, String authCode, String password) {
		Long checkUserId = checkAuthCode(authCode);
		userAuthService.expire(authCode);
		if(userId!=null && userId.intValue() == checkUserId.intValue()){
			if(StringUtils.isBlank(password)){
				throw new UserException(ResultEnum.PARAM_ERROR);
			}
			userService.resetPassword(userId,password);
		}else{
			throw new UserException(ResultEnum.PARAM_ERROR);
		}
	}
	
}
